package com.pcbly.web.components.utils.property;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.time.FastDateFormat;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import com.pcbly.web.OfficeHome;
import com.pcbly.web.components.utils.LocaleUtils;



@SuppressWarnings("unchecked")
public class OfficeGlobals {
	private static final Logger log = LogManager.getLogger(OfficeGlobals.class);
	static final String DEFAULT_CHAR_ENCODING = "UTF-8";
	private static Locale locale = null;
	private static TimeZone timeZone = null;
	private static String characterEncoding = null;
	private static FastDateFormat dateFormat = null;
	private static FastDateFormat dateTimeFormat = null;
	private static volatile boolean failedLoading = false;
	private static Date startupDate = new Date();
	private static volatile boolean whiteLabel = false;
	private static volatile boolean initWhiteLabel = false;
	private static volatile boolean evalBuild = false;
	private static volatile boolean initEvalBuild = false;
	private static volatile String revision = "Custom";
	private static volatile boolean initRevision = false;
	private static String name;
	private static final Object officeHomeLock = new Object();

	private static volatile OfficeProperties setupProperties = null;
	private static volatile OfficeProperties properties = null;
	private static volatile OfficeProperties localizedProperties = null;

	public static boolean isHidden(String propName) {
		if (propName == null) {
			return false;
		} else {
			String propNameLower = propName.toLowerCase();
			return propNameLower.indexOf("passwd") > -1
					|| propNameLower.indexOf("password") > -1
					&& propNameLower.indexOf("passwordreset") == -1
					|| propNameLower.indexOf("cookiekey") > -1
					|| propNameLower.indexOf("secret") > -1;
		}
	}

	public static void reset() {
		synchronized (officeHomeLock) {
			startupDate = new Date();
			whiteLabel = false;
			initWhiteLabel = false;
			setupProperties = null;
			properties = null;
			localizedProperties = null;
		}
	}

	public static void resetLocalization() {
		locale = null;
		timeZone = null;
		characterEncoding = null;
		dateFormat = null;
		dateTimeFormat = null;
	}

	public static Date getStartupDate() {
		return new Date(startupDate.getTime());
	}

	public static Locale getLocale() {
		if (locale == null) {
			String language = (String) getOfficeProperties().get(
					"locale.language");
			if (language == null)
				language = "";
			String country = (String) getOfficeProperties().get(
					"locale.country");
			if (country == null)
				country = "";
			if (language.equals("") && country.equals(""))
				locale = Locale.getDefault();
			else
				locale = new Locale(language, country);
		}
		return locale;
	}

	public static String getName() {
		if (name == null) {
			String propName = (String) getOfficeProperties().get("office.name");
			if (propName != null)
				name = propName;
		}
		if (name == null) {
			String envName = System.getProperty("office.name", null);
			if (envName != null) {
				name = envName;
			} else {
				log.info("No component name specified. Defaulting to 'sbs'.");
				name = "sbs";
			}
		}
		return name;
	}

	public static void setLocale(Locale newLocale) {
		String s = newLocale.getCountry();
		String s1 = "locale.country";
		setOfficeProperty(s1, s);
		String s2 = newLocale.getLanguage();
		String s3 = "locale.language";
		setOfficeProperty(s3, s2);
		resetLocalization();
	}
//	public static getInstance(){
//		
//	}
	public static String getCharacterEncoding() {
		if (characterEncoding == null) {
			String encoding = getLocalProperty("locale.characterEncoding");
			if (encoding != null)
				characterEncoding = encoding;
			String charEncoding = getOfficeProperty("locale.characterEncoding");
			if (charEncoding != null)
				characterEncoding = charEncoding;
			else if (characterEncoding == null)
				characterEncoding = "UTF-8";
		}
		return characterEncoding;
	}

	public static void setCharacterEncoding(String characterEncoding)
			throws UnsupportedEncodingException {
		if (!LocaleUtils.isValidCharacterEncoding(characterEncoding)) {
			throw new UnsupportedEncodingException((new StringBuilder())
					.append("Invalid character encoding: ").append(
							characterEncoding).toString());
		} else {
			String s = characterEncoding;
			String s1 = "locale.characterEncoding";
			setOfficeProperty(s1, s);
			resetLocalization();
			return;
		}
	}

	public static TimeZone getTimeZone() {
		if (timeZone == null)
			if (properties != null) {
				String timeZoneID = (String) properties.get("locale.timeZone");
				if (timeZoneID == null)
					timeZone = TimeZone.getDefault();
				else
					timeZone = TimeZone.getTimeZone(timeZoneID);
			} else {
				return TimeZone.getDefault();
			}
		return timeZone;
	}

	public static void setTimeZone(TimeZone newTimeZone) {
		String s = newTimeZone.getID();
		String s1 = "locale.timeZone";
		setOfficeProperty(s1, s);
		resetLocalization();
	}

	public static String formatDate(Date date) {
		if (dateFormat == null)
			if (properties != null) {
				dateFormat = FastDateFormat.getDateInstance(2, getTimeZone(),
						getLocale());
			} else {
				FastDateFormat instance = FastDateFormat.getDateInstance(2,
						getTimeZone(), getLocale());
				return instance.format(date);
			}
		return dateFormat.format(date);
	}

	public static String formatDateTime(Date date) {
		if (dateTimeFormat == null)
			if (properties != null) {
				dateTimeFormat = FastDateFormat.getDateTimeInstance(2, 2,
						getTimeZone(), getLocale());
			} else {
				FastDateFormat instance = FastDateFormat.getDateTimeInstance(2,
						2, getTimeZone(), getLocale());
				return instance.format(date);
			}
		return dateTimeFormat.format(date);
	}

	public static String getDefaultBaseURL() {
		String url = System.getProperty("jiveURL");
		if (url == null || "".equals(url))
			url = getOfficeProperty("jiveURL");
		if (url != null)
			url = url.trim();
		if (url == null || "".equals(url)) {
			log
					.warn("No URL set for property 'jiveURL', this will cause links to fail.");
			url = "";
		} else {
			for (; url.length() > 0 && url.charAt(url.length() - 1) == '/'; url = url
					.substring(0, url.length() - 1))
				;
		}
		return url;
	}

	

	public static String getOfficeHome() {
		return OfficeHome.getOfficeHomePath();
	}


	public static String getPluginDirectory() {
		return OfficeHome.getPlugins().getAbsolutePath();
	}

	public static boolean isSetup() {
		return "true".equals(getLocalProperty("setup"));
	}

	public static String getLocalProperty(String name) {
		return (String) getSetupProperties().get(name);
	}

	public static int getLocalProperty(String name, int defaultValue) {
		String value;
		value = getLocalProperty(name);
		if (value == null)
			return defaultValue;
		try {
			return Integer.parseInt(value);
		} catch (NumberFormatException nfe) {
			return defaultValue;
		}
	}

	public static String getLocalProperty(String name, String defaultValue) {
		String value = getLocalProperty(name);
		if (value != null)
			return value;
		else
			return defaultValue;
	}

	public static List getLocalProperties(String parent) {
		Collection propNames = getSetupProperties().getChildrenNames(parent);
		List values = new ArrayList();
		Iterator i$ = propNames.iterator();
		do {
			if (!i$.hasNext())
				break;
			String propName = (String) i$.next();
			String value = getOfficeProperty((new StringBuilder()).append(
					parent).append(".").append(propName).toString());
			if (value != null)
				values.add(value);
		} while (true);
		return values;
	}

	public static void setLocalProperty(String name, String value) {
		getSetupProperties().put(name, value);
	}

	public static void setLocalProperties(Map propertyMap) {
		getSetupProperties().putAll(propertyMap);
	}

	public static void deleteLocalProperty(String name) {
		try {
			getSetupProperties().remove(name);
		} catch (Exception e) {
			log.error(e);
		}
	}

	public static String getOfficeProperty(String name) {
		return (String) getOfficeProperties().get(name);
	}

	public static String getOfficeProperty(String name, String defaultValue) {
		String value = (String) getOfficeProperties().get(name);
		if (value != null)
			return value;
		else
			return defaultValue;
	}

	private static OfficeProperties getOfficeProperties() {
		if (properties == null) {
			getSetupProperties();
		}
		return properties;
	}

	public static List getOfficePropertyNames() {
		return new ArrayList(getOfficeProperties().getPropertyNames());
	}

	public static List getOfficePropertyNames(String parent) {
		getOfficeProperties();
		return new ArrayList(getOfficeProperties().getChildrenNames(parent));
	}

	public static List getOfficeProperties(String parent) {
		getOfficeProperties();
		Collection propertyNames = getOfficeProperties().getChildrenNames(
				parent);
		List values = new ArrayList();
		Iterator i$ = propertyNames.iterator();
		do {
			if (!i$.hasNext())
				break;
			String propertyName = (String) i$.next();
			String value = getOfficeProperty(propertyName);
			if (value != null)
				values.add(value);
		} while (true);
		return values;
	}

	public static int getOfficeIntProperty(String name, int defaultValue) {
		try {
			String value;
			value = getOfficeProperty(name);
			if (value == null)
				return defaultValue;
			return Integer.parseInt(value);
		} catch (NumberFormatException nfe) {
			return defaultValue;
		}
	}

	public static boolean getOfficeBooleanProperty(String name) {
		return Boolean.valueOf(getOfficeProperty(name)).booleanValue();
	}

	

	public static void setOfficeProperty(String name, String value) {
		getOfficeProperties().put(name, value);
	}

	public static void setOfficeProperties(Map propertyMap) {
		getOfficeProperties().putAll(propertyMap);
	}

	public static void deleteOfficeProperty(String name) {
		getOfficeProperties().remove(name);
	}

	public static String getLocalizedOfficeProperty(String name, Locale locale) {
		return (String) getLocalizedProps().get(
				(new StringBuilder()).append(name).append(".").append(locale)
						.toString());
	}

	public static List getLocalizedPropertyLocales(String name) {
			return Collections.emptyList();
	}

	public static void setLocalizedOfficeProperty(String name, String value,
			Locale locale) {

		getLocalizedProps().put(
				(new StringBuilder()).append(name).append(".").append(
						locale.toString()).toString(), value);
	}

	public static void deleteLocalizedOfficeProperty(String name, Locale locale) {
		getLocalizedProps().remove(
				(new StringBuilder()).append(name).append(".").append(
						locale.toString()).toString());
	}

	private static OfficeProperties getLocalizedProps() {
		if (localizedProperties == null) {
			getSetupProperties();
		}
		return localizedProperties;
	}

	private static OfficeProperties getSetupProperties()
    {
        if(failedLoading)
            return EmptyOfficeProperties.getInstance();
        if(setupProperties != null)
            return null;
        if(setupProperties != null)
            return setupProperties;
        File jh = OfficeHome.getOfficeHome();
        if(!jh.exists())
            log.fatal((new StringBuilder()).append("The specified officeHome directory does not exist (").append(jh.getAbsolutePath()).append(")").toString());
        else
        if(!jh.canRead() || !jh.canWrite())
            log.fatal((new StringBuilder()).append("The operating system user running this application can not read and write to the specified officeHome directory (").append(jh.getAbsolutePath()).append("). Please grant the executing user ").append("read and write permissions.").toString());
        try{
        setupProperties = new XMLOfficeProperties(OfficeHome.getConfigurationFile().getAbsolutePath());
        }catch(IOException e){
        	log.error(e.getMessage(),e);
        }
        return setupProperties;
    }

	public static boolean isWhiteLabel() {
		if (!initWhiteLabel) {
			whiteLabel = true;
			initWhiteLabel = true;
		}
		return whiteLabel;
	}

	public static boolean isEvalBuild() {
		if (!initEvalBuild) {
			evalBuild = "true".equals(getBuildProperty("evaluation"));
			initEvalBuild = true;
		}
		return evalBuild;
	}

	public static String getRevision() {
		if (!initRevision) {
			String s = getBuildProperty("revision");
			if (s != null)
				revision = s;
			initRevision = true;
		}
		return revision;
	}

	public static String getBuildProperty(String name) {
		return name;
	}

	public static Map getUnmodifiableMap() {
		return Collections.unmodifiableMap(getOfficeProperties());
	}

	public static void setSpiProperty(String clazz, String name, String value) {
		String s = value;
		String s1 = spiKeyToOffice(clazz, name);
		setOfficeProperty(s1, s);
	}

	private static String spiKeyToOffice(String clazz, String name) {
		return String.format("%s%s", new Object[] { spiPrefix(clazz), name });
	}

	private static String spiPrefix(String clazz) {
		return String.format("__office.spi.%s:", new Object[] { clazz });
	}

	public static String getSpiProperty(String spiClass, String name) {
		return getOfficeProperty(spiKeyToOffice(spiClass, name));
	}

	private static String jiveKeyToSpiKey(String clazz, String name) {
		return name.replace(spiPrefix(clazz), "");
	}

	public static Map getSpiProperties(String spiClass) {
		List names = getOfficePropertyNames();
		Map spiConfig = new HashMap();
		Iterator i$ = names.iterator();
		do {
			if (!i$.hasNext())
				break;
			String property = (String) i$.next();
			if (property.indexOf(spiPrefix(spiClass)) != -1)
				spiConfig.put(jiveKeyToSpiKey(spiClass, property),
						getOfficeProperty(property));
		} while (true);
		return spiConfig;
	}

	public static void setSpiProperties(String spiClass, Map config) {
		String key;
		for (Iterator i$ = config.keySet().iterator(); i$.hasNext(); setSpiProperty(
				spiClass, key, (String) config.get(key)))
			key = (String) i$.next();

	}

	public static boolean isDebugMode() {
		return getOfficeBooleanProperty("office.devMode", false)
				|| BooleanUtils.toBoolean(System.getProperty("office.devMode"));
	}

	public static boolean getOfficeBooleanProperty(String string, boolean b) {
		return false;
	}
}
